
#include <string.h>
#include <stdlib.h>

#include "../cute/cute.h"
#include "../cute/ide_listener.h"
#include "../cute/cute_runner.h"

#include "Registro.h"
#include "NodoHoja.h"
#include "NodoIndice.h"
#include "ArbolBSharp.h"
#include "ReferenciaNodo.h"

using namespace std;


void CrearRegistroTest()
{
	Registro* nuevoRegistro = new Registro("HOLA", "Mundo");
	ASSERT(nuevoRegistro != NULL);
	ASSERT_EQUAL("HOLA",nuevoRegistro->getKey());
	ASSERT_EQUAL("Mundo",nuevoRegistro->getDato());
	delete nuevoRegistro;
}

void runRegistroTests()
{
	cute::suite s;

	s.push_back(CUTE(CrearRegistroTest));
	cute::ide_listener lis;
	cute::makeRunner(lis)(s, "runRegistroTests");
}

void CrearNodoIndiceTest(){
	NodoIndice* nodo = new NodoIndice();
	ASSERT(nodo != NULL);
	delete nodo;
}

void InsertarKeysYIdsNodoIndiceTest()
{
	string keyPrimera = "0000";
	NodoIndice* nodito = new NodoIndice();

	nodito->setId(0);
	nodito->insertarKey(keyPrimera);

	ASSERT(strcmp(nodito->getPrimerKey().c_str(),keyPrimera.c_str()) == 0);
	delete nodito;
}


void GetIdNodoHojaTest(){
	Nodo* hojita = new NodoHoja();
	hojita->setId(5);
	ASSERT_EQUAL(5,hojita->getId());
	delete hojita;
}


void InsertarRegistrosNodoHojaTest(){
	Registro* registroUno = new Registro("1","");
	Registro* registroDos = new Registro("2","");
	Registro* registroTres = new Registro("3","");
	Registro* registroA = new Registro("A","");

	NodoHoja* hojita = new NodoHoja();

	hojita->insertarRegistro(registroTres);
	hojita->insertarRegistro(registroA);
	hojita->insertarRegistro(registroUno);
	hojita->insertarRegistro(registroDos);

	ASSERT_EQUAL(0,hojita->getPosicionRegistro(registroUno));
	ASSERT_EQUAL(1,hojita->getPosicionRegistro(registroDos));
	ASSERT_EQUAL(2,hojita->getPosicionRegistro(registroTres));
	ASSERT_EQUAL(3,hojita->getPosicionRegistro(registroA));

	delete registroUno;
	delete registroDos;
	delete registroTres;
	delete registroA;
}

void RegistroDuplicadoEnNodoHojaTest(){
	Registro* registroUno = new Registro((char*)"1",(char*)"");

	NodoHoja* hojita = new NodoHoja();

	hojita->insertarRegistro(registroUno);
	ASSERT_EQUAL(1,hojita->insertarRegistro(registroUno));
	delete hojita;
}

void RegistroInexistenteEnNodoHojaTest(){
	Registro* registroUno = new Registro((char*)"1",(char*)"");
	Registro* registroA = new Registro((char*)"A",(char*)"");

	NodoHoja* hojita = new NodoHoja();

	hojita->insertarRegistro(registroUno);
	ASSERT_EQUAL(-1,hojita->getPosicionRegistro(registroA));
	delete hojita;
}


void runNodoHojaTests(){
	cute::suite s;
	s.push_back(CUTE(InsertarRegistrosNodoHojaTest));
	s.push_back(CUTE(RegistroDuplicadoEnNodoHojaTest));
	s.push_back(CUTE(RegistroInexistenteEnNodoHojaTest));
	s.push_back(CUTE(GetIdNodoHojaTest));
	cute::ide_listener lis;
	cute::makeRunner(lis)(s, "runNodoHojaTests");
}


void runPersistirRegistroTest(){

	fstream archivo;
	string fileName = "persistirRegistrito.dat";

	Registro* registrito = new Registro("HOLA ","Mundo");
	Registro* registritoRecuperado = new Registro();

	int tamanioEstructura = 512;

	ManejadorArchivo::Crear(fileName.c_str(),&archivo);

	stringstream iosIN(ios_base::in| ios_base::out| ios_base::binary);

	iosIN.write(registrito->toString().c_str(),registrito->toString().length());

	ManejadorArchivo::EscribirEstructura(&archivo,&iosIN,0,tamanioEstructura);
	ManejadorArchivo::Cerrar(&archivo);

	stringstream iosOUT(ios_base::in| ios_base::out| ios_base::binary);

	ManejadorArchivo::Abrir(fileName.c_str(),&archivo);
	ManejadorArchivo::RecuperarEstructura(&archivo,&iosOUT,0,tamanioEstructura);

	registritoRecuperado->fromString(&iosOUT.str());

	ManejadorArchivo::Cerrar(&archivo);

	ASSERTM("Inconsistencia en key de registro", strcmp(registrito->getKey().c_str(), registritoRecuperado->getKey().c_str()) == 0);
	ASSERTM("Inconsistencia en dato de registro", strcmp(registrito->getDato().c_str(), registritoRecuperado->getDato().c_str()) == 0);

	delete(registrito);
	delete(registritoRecuperado);
}



void runPersistirNodoHojaTest()
{
	fstream archivo;
	string fileName = "persistirHojita.dat";
	int idHojita = 2300;
	int alturaHojita = 3100;
	int idHojitaSiguiente = 598;

	NodoHoja* hojita = new NodoHoja();
	hojita->setId(idHojita);
	hojita->setAltura(alturaHojita);
	hojita->setIdHojaSiguiente(idHojitaSiguiente);

	NodoHoja* hojitaRecuperada = new NodoHoja();

	int tamanioEstructura = 1024;

	Registro* registroUno = new Registro("1","HOLA askfjlñkasjfklasf");
	Registro* registroDos = new Registro("2","AL aksfjñlkasdjflñksdjfsdl !#$%&/()=");
	Registro* registroTres = new Registro("3","ARBOLITO! 123456");

	hojita->insertarRegistro(registroUno);
	hojita->insertarRegistro(registroDos);
	hojita->insertarRegistro(registroTres);

	ManejadorArchivo::Crear(fileName.c_str(),&archivo);

	stringstream iosIN(ios_base::in| ios_base::out| ios_base::binary);

	string buffer = "";

	buffer = hojita->toString();

	iosIN.write(buffer.c_str(), buffer.length());

	ManejadorArchivo::EscribirEstructura(&archivo,&iosIN,0,tamanioEstructura);
	ManejadorArchivo::Cerrar(&archivo);

	stringstream iosOUT(ios_base::in| ios_base::out| ios_base::binary);

	ManejadorArchivo::Abrir(fileName.c_str(),&archivo);
	ManejadorArchivo::RecuperarEstructura(&archivo,&iosOUT,0,tamanioEstructura);


	hojitaRecuperada->fromString(iosOUT.str());

	ManejadorArchivo::Cerrar(&archivo);

	cout<<"ID HOJA: "<< hojitaRecuperada->getId()<<endl;
	//Recorre la lista de la hoja recuperada e imprime sus valores
	list<Registro*>* listRegistros = hojitaRecuperada->getListaRegistros();
	list<Registro*>::iterator it = listRegistros->begin();
	while (it != listRegistros->end())
	{
		Registro* reg = ((Registro*)*it);
		cout<<reg->getKey()<<endl;
		it++;
	}


	ASSERTM("Inconsistencia en los ids de las hojas", hojita->getId() == hojitaRecuperada->getId());
	ASSERTM("Inconsistencia en las alturas de las hojas", hojita->getAltura() == hojitaRecuperada->getAltura());
	ASSERTM("Inconsistencia en la cantidad de registros de las hojas", hojita->getCantidadRegistros() == hojitaRecuperada->getCantidadRegistros());
	ASSERTM("Inconsistencia en el id hoja siguiente de las hojas", hojita->getIdHojaSiguiente() == hojitaRecuperada->getIdHojaSiguiente());


	delete(hojita);
	delete(hojitaRecuperada);

}


void runPersistirNodoIndiceTest()
{
	fstream archivo;
	string fileName = "persistirIndice.dat";
	int id= 28950;
	int altura= 31000;


	NodoIndice* nodoIndice = new NodoIndice();
	nodoIndice->setId(id);
	nodoIndice->setAltura(altura);


	NodoIndice* indiceRecuperado = new NodoIndice();

	int tamanioEstructura = 2048;

	nodoIndice->insertarKey("Soy Mil");
	nodoIndice->insertarKey("Soy 2 Mil");
	nodoIndice->insertarKey("Soy 3 Mil");
	nodoIndice->insertarKey("Soy 4 Mil");

	ReferenciaNodo* refHijoCero = new ReferenciaNodo();
	ReferenciaNodo* refHijoUno 	= new ReferenciaNodo();
	ReferenciaNodo* refHijoDos	= new ReferenciaNodo();
	ReferenciaNodo* refHijoTres	= new ReferenciaNodo();
	ReferenciaNodo* refHijoCuatro= new ReferenciaNodo();

	refHijoCero->idNodo = 2300;
	refHijoUno->idNodo 	= 2300;
	refHijoDos->idNodo 	= 2300;
	refHijoTres->idNodo = 2300;
	refHijoCuatro->idNodo= 2300;


	nodoIndice->referenciaAHijos.push_front(refHijoCero);
	nodoIndice->referenciaAHijos.push_front(refHijoUno);
	nodoIndice->referenciaAHijos.push_front(refHijoDos);
	nodoIndice->referenciaAHijos.push_front(refHijoTres);
	nodoIndice->referenciaAHijos.push_front(refHijoCuatro);


	ManejadorArchivo::Crear(fileName.c_str(),&archivo);

	stringstream iosIN(ios_base::in| ios_base::out| ios_base::binary);

	string buffer = "";

	buffer = nodoIndice->toString();

	iosIN.write(buffer.c_str(), buffer.length());

	ManejadorArchivo::EscribirEstructura(&archivo,&iosIN,0,tamanioEstructura);
	ManejadorArchivo::Cerrar(&archivo);

	delete(refHijoCero);
	delete(refHijoUno);
	delete(refHijoDos);
	delete(refHijoTres);
	delete(refHijoCuatro);

	stringstream iosOUT(ios_base::in| ios_base::out| ios_base::binary);


	ManejadorArchivo::Abrir(fileName.c_str(),&archivo);
	ManejadorArchivo::RecuperarEstructura(&archivo,&iosOUT,0,tamanioEstructura);

	indiceRecuperado->fromString(iosOUT.str());

	ManejadorArchivo::Cerrar(&archivo);


	 //Recorre el indice recuperado e imprime sus valores
	list<string*>::list listKeys = indiceRecuperado->getKeys();
	list<string*>::iterator it = listKeys.begin();
	while (it != listKeys.end())
	{
		string* key = (string*)*it;
		cout<<key<<endl;
		it++;
	}

	 //Recorre el indice recuperado e imprime sus valores de referncia a nodos
	list<ReferenciaNodo*>::list listRefHijos = indiceRecuperado->referenciaAHijos;
	list<ReferenciaNodo*>::iterator itHijos = listRefHijos.begin();
	while (itHijos != listRefHijos.end())
	{
		ReferenciaNodo* ref = ((ReferenciaNodo*)*itHijos);
		cout<<((int)ref->idNodo >> 32)<<endl;
		itHijos++;
	}


	ASSERTM("Indice ID Inconsistencia", nodoIndice->getId() == indiceRecuperado->getId());
	ASSERTM("Indice Altura Inconsistencia en las alturas de las hojas", nodoIndice->getAltura() == indiceRecuperado->getAltura());
	//ASSERTM("Indice Inconsistencia en la cantidad de registros de las hojas", nodoIndice->getCantidadKeys() == indiceRecuperado->getCantidadKeys());
	//ASSERTM("Inconsistencia en el id hoja siguiente de las hojas", strcm((string)(nodoIndice->getKeys().begin())).c_str(),((string)(indiceRecuperado->getKeys().begin())).c_str()a) == 0);



	delete(nodoIndice);
	delete(indiceRecuperado);

}

void runPersistirRaizTest(){

	ArbolBSharp* arbolito = new ArbolBSharp("persistirArbolito.dat",256);

	Registro* registroUno = new Registro((char*)"1",(char*)"HOLA");
	Registro* registroDos = new Registro((char*)"2",(char*)"AL");
	Registro* registroTres = new Registro((char*)"3",(char*)"ARBOLITO");

	arbolito->insertarRegistro(registroUno);
	arbolito->insertarRegistro(registroDos);
	arbolito->insertarRegistro(registroTres);

	arbolito->persistirNodo4Tests(arbolito->getRaiz());
}

void runNodoIndiceTests()
{
	cute::suite s;

	//Add test here:
	s.push_back(CUTE(CrearNodoIndiceTest));
	s.push_back(CUTE(InsertarKeysYIdsNodoIndiceTest));
	s.push_back(CUTE(runPersistirNodoIndiceTest));
	cute::ide_listener lis;
	cute::makeRunner(lis)(s, "runNodoIndiceTests");
}

void runPersistirArbolTests(){
	cute::suite s;

	s.push_back(CUTE(runPersistirRegistroTest));
	s.push_back(CUTE(runPersistirNodoHojaTest));
	s.push_back(CUTE(runPersistirRaizTest));
	cute::ide_listener lis;
	cute::makeRunner(lis)(s, "runPersistirRaizArbolTests");
}

void runCrearArbolTest()
{
	//ArbolBSharp arbolito = new ArbolBSharp();

}



void makeCrearArbolTests()
{
	cute::suite s;
	s.push_back(CUTE(runPersistirRegistroTest));
	s.push_back(CUTE(runPersistirNodoHojaTest));
	s.push_back(CUTE(runPersistirNodoIndiceTest));

	cute::ide_listener lis;
	cute::makeRunner(lis)(s, "runCrearArbolTest");

}


int main()
{
	runRegistroTests();
	runNodoHojaTests();
	runNodoIndiceTests();
	runPersistirArbolTests();
	//makeCrearArbolTests();

    return 0;
}













